package com.isesol.seckill.service.impl;

import com.isesol.arch.common.uitil.redis.*;
import com.isesol.seckill.*;
import com.isesol.seckill.enums.*;
import com.isesol.seckill.result.*;
import com.isesol.seckill.service.*;
import org.slf4j.*;
import org.springframework.stereotype.*;

import javax.annotation.*;
import java.net.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

/**
 * 秒杀接口实现
 *
 * @author Peter Zhang
 */
@Service("countService")
public class CountServiceImpl implements CountService {

    protected Logger LOGGER = LoggerFactory.getLogger(getClass());

    @Resource
    RedisUtil redisUtil;

    /**
     * reset实例数
     */
    public void resetInstanceCount(){

        CountInfo.INSTANCE_COUNT = 0;
    }

    /**
     * 注册实例
     */
    public void regInstanceCount(){

        try{
            String hostName=InetAddress.getLocalHost().getHostName();

            redisUtil.sadd("seckill-instance", hostName);

        }catch(Exception e){

            LOGGER.error("regInstanceCount error",e);

        }

    }

    /**
     * 获取实例数
     */
    public long getInstanceCount(){

        try{

            return redisUtil.scard("seckill-instance");

        }catch(Exception e){

            LOGGER.error("getInstanceCount error",e);
        }

        return 0;
    }

    /**
     * 设置实例数
     *
     * @param val
     */
    public void setInstanceCount(long val) {

        CountInfo.INSTANCE_COUNT = val;

        LOGGER.info("【seckill/实例数】,val={}", val);
    }

    /**
     * 设置库存
     *
     * @param key
     * @param val
     */
    public synchronized void setStockInfo(String key, long val) {

        CountInfo.STOCK_MAP.put(key, new AtomicLong(val));

        LOGGER.info("【seckill/设置库存】 key={},val={}", key, val);

    }

    /**
     * 设置发生情况
     *
     * @param key
     * @param val
     */
    public synchronized void setSalesInfo(String key, long val) {


        CountInfo.SALES_MAP.put(key, new AtomicLong(val));
    }

    /**
     * 发生情况加
     *
     * @param key
     */
    public long incSalesInfo(String key) {

        return CountInfo.SALES_MAP.get(key).incrementAndGet();
    }

    /**
     * 验证码id加
     *
     * @param key
     * @return
     */
    public Result<CaptchaResult> incCaptchaIdCount(String key) {


        SecKillStatusEnum secKillStatusEnum=SecKillStatusInfo.SEC_KILL_STATUS_MAP.get(key);
        /**
         * 先判断是否可以秒杀
         */
        if (null==secKillStatusEnum || !secKillStatusEnum.equals(SecKillStatusEnum.NORMAL)) {

            return assembleFailResult(ErrorCode.SEC_KILL_END, ErrorCode.SEC_KILL_END.getMessage());

        } else {

            LongAdder captchaCount = CountInfo.CAPTCHA_COUNT_MAP.get(key);

            if (null == captchaCount) {

                return assembleFailResult(ErrorCode.CAPTCHA_INIT_ERROR, ErrorCode.CAPTCHA_INIT_ERROR.getMessage());

            } else {

                captchaCount.add(CountInfo.INSTANCE_COUNT);

                CaptchaResult captchaResult = new CaptchaResult();
                captchaResult.setCaptchaId(captchaCount.longValue());

                return assembleSuccessResult(captchaResult);

            }
        }


    }

    /**
     * 获取库存情况
     *
     * @param key
     * @return
     */
    public long getStockInfo(String key) {

        return CountInfo.STOCK_MAP.get(key).longValue();
    }

    /**
     * 获取发生情况
     *
     * @param key
     */
    public long getSalesInfo(String key) {

        return CountInfo.SALES_MAP.get(key).longValue();
    }

    /**
     * 组装失败返回
     *
     * @param errorCode
     * @param errorMessage
     * @return
     */
    private Result<CaptchaResult> assembleFailResult(ErrorCode errorCode, String errorMessage) {

        Result<CaptchaResult> result = new Result<>();

        result.setSuccess(false);
        result.setErrorCode(errorCode);
        result.setErrorMessage(errorMessage);

        return result;
    }

    /**
     * 组装失败返回
     *
     * @param captchaResult
     * @return
     */
    private Result<CaptchaResult> assembleSuccessResult(CaptchaResult captchaResult) {

        Result<CaptchaResult> result = new Result<>();

        result.setSuccess(true);
        result.setModel(captchaResult);

        return result;
    }
}
